//////////////////////////////////////////ok
#include"stdafx.h"
#include "bochs.h"



void IA32_CPU::check_exceptionsSSE(int exceptions_flags)
{
  int unmasked = ~(MXCSR.get_exceptions_masks()) & exceptions_flags;
  MXCSR.set_exceptions(exceptions_flags);

  if (unmasked) 
  {
     if( cr4.get_OSXMMEXCPT())
        exception(IA32_XM_EXCEPTION, 0, 0);
     else
        exception(IA32_UD_EXCEPTION, 0, 0);
  }
}

static void mxcsr_to_softfloat_status_word(float_status_t &status, bx_mxcsr_t mxcsr)
{
  status.float_exception_flags = 0; // clear exceptions before execution
  status.float_nan_handling_mode = float_first_operand_nan;
  status.float_rounding_mode = mxcsr.get_rounding_mode();
  status.flush_underflow_to_zero = (mxcsr.get_flush_masked_underflow() && mxcsr.get_UM()) ? 1 : 0;
}

// handle DAZ
static float32 handleDAZ(float32 op)
{
  if (float32_class(op) == float_denormal) 
	  op &= ((Bit32u)(1) << 31);
  return op;                      
}

static float64 handleDAZ(float64 op)
{
  if (float64_class(op) == float_denormal) 
	  op &= ((Bit64u)(1) << 63);
  return op;
}

/* Comparison predicate for CMPSS/CMPPS instructions */
static float32_compare_method compare32[4] = {
  float32_eq, 
  float32_lt, 
  float32_le, 
  float32_unordered
};

/* Comparison predicate for CMPSD/CMPPD instructions */
static float64_compare_method compare64[4] = {
  float64_eq, 
  float64_lt, 
  float64_le, 
  float64_unordered
};


void IA32_CPU::CVTPI2PS_VpsQq(Ia32_Instruction_c *i)
{
   prepareSSE();
   prepareFPU2MMX();

  Ia32_PackedMmxRegister op;
  Ia32PackedXmmRegister result;

  /* op is a register or memory reference */
  if (i->modC0()) 
  {
    op = IA32_READ_MMX_REG(i->rm());
  }
  else 
  {
    read_virtual_qword(i->seg(), IA32_RMAddr(i), (Bit64u *) &op);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);
  result.xmm32u(0) = int32_to_float32(MMXUD0(op), status_word);
  result.xmm32u(1) = int32_to_float32(MMXUD1(op), status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG_LO_QWORD(i->nnn(), result.xmm64u(0));
}

/* 
 * Opcode: 66 0F 2A
 * Convert two 32bit signed integers from MMX/MEM to two double precision FP
 * Possible floating point exceptions: -
 */
void IA32_CPU::CVTPI2PD_VpdQd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 2A
 * Convert one 32bit signed integer to one double precision FP
 * Possible floating point exceptions: -
 */
void IA32_CPU::CVTSI2SD_VsdEd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F 2A
 * Convert one 32bit signed integer to one single precision FP
 * When a conversion is inexact, the value returned is rounded according
 * to rounding control bits in MXCSR register.
 * Possible floating point exceptions: #P
 */
void IA32_CPU::CVTSI2SS_VssEd(Ia32_Instruction_c *i)
{
  
   prepareSSE();
  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);
  Float32 result;

  {
    Bit32u op;

    /* op is a register or memory reference */
    if (i->modC0()) {
      op = IA32_READ_32BIT_REG(i->rm());
    }
    else {
      /* pointer, segment address pair */
      read_virtual_dword(i->seg(), IA32_RMAddr(i), &op);
    }

    result = int32_to_float32(op, status_word);
  }
 
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG_LO_DWORD(i->nnn(), result);
}

/* 
 * Opcode: 0F 2C
 * Convert two single precision FP numbers to two signed doubleword integers 
 * in MMX using truncation if the conversion is inexact
 * Possible floating point exceptions: #I, #P
 */
void IA32_CPU::CVTTPS2PI_PqWps(Ia32_Instruction_c *i)
{
   prepareSSE();
   prepareFPU2MMX();

  Bit64u op;
  Ia32_PackedMmxRegister result;

  if (i->modC0()) 
  {
    op = IA32_READ_XMM_REG_LO_QWORD(i->rm());
  }
  else 
  {
    read_virtual_qword(i->seg(), IA32_RMAddr(i), &op);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);
  Float32 r0 = (Float32)(op & 0xFFFFFFFF);
  Float32 r1 = (Float32)(op >> 32);
  MMXUD0(result) = float32_to_int32_round_to_zero(r0, status_word);
  MMXUD1(result) = float32_to_int32_round_to_zero(r1, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_MMX_REG(i->nnn(), result);
}

/* 
 * Opcode: 66 0F 2C
 * Convert two double precision FP numbers to two signed doubleword integers 
 * in MMX using truncation if the conversion is inexact
 * Possible floating point exceptions: #I, #P
 */
void IA32_CPU::CVTTPD2PI_PqWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 2C
 * Convert one double precision FP number to doubleword integer using 
 * truncation if the conversion is inexact
 * Possible floating point exceptions: #I, #P
 */
void IA32_CPU::CVTTSD2SI_GdWsd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F 2C
 * Convert one single precision FP number to doubleword integer using 
 * truncation if the conversion is inexact
 * Possible floating point exceptions: #I, #P
 */
void IA32_CPU::CVTTSS2SI_GdWss(Ia32_Instruction_c *i)
{
   prepareSSE();

  Float32 op;

  if (i->modC0()) 
  {
    op = IA32_READ_XMM_REG_LO_DWORD(i->rm());
  }
  else 
  {
    read_virtual_dword(i->seg(), IA32_RMAddr(i), &op);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);

  Bit32u result = float32_to_int32_round_to_zero(op, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_32BIT_REG(i->nnn(), result);

}

/*
 * Opcode: 0F 2D
 * Convert two single precision FP numbers to two signed doubleword integers 
 * in MMX register. When a conversion is inexact, the value returned is 
 * rounded according to rounding control bits in MXCSR register.
 * Possible floating point exceptions: #I, #P
 */
void IA32_CPU::CVTPS2PI_PqWps(Ia32_Instruction_c *i)
{
   prepareSSE();
   prepareFPU2MMX();

  Bit64u op;
  Ia32_PackedMmxRegister result;

  if (i->modC0()) 
  {
    op = IA32_READ_XMM_REG_LO_QWORD(i->rm());
  }
  else 
  {
    read_virtual_qword(i->seg(), IA32_RMAddr(i), &op);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);
  Float32 r0 = (Float32)(op & 0xFFFFFFFF);
  Float32 r1 = (Float32)(op >> 32);
  MMXUD0(result) = float32_to_int32(r0, status_word);
  MMXUD1(result) = float32_to_int32(r1, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_MMX_REG(i->nnn(), result);
}

/* 
 * Opcode: 66 0F 2D
 * Convert two double precision FP numbers to two signed doubleword integers 
 * in MMX register. When a conversion is inexact, the value returned is 
 * rounded according to rounding control bits in MXCSR register.
 * Possible floating point exceptions: #I, #P
 */
void IA32_CPU::CVTPD2PI_PqWpd(Ia32_Instruction_c *i)
{                      
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 2D
 * Convert one double precision FP number to doubleword integer
 * When a conversion is inexact, the value returned is rounded according
 * to rounding control bits in MXCSR register.
 * Possible floating point exceptions: #I, #P
 */
void IA32_CPU::CVTSD2SI_GdWsd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/*
 * Opcode: F3 0F 2D
 * Convert one single precision FP number to doubleword integer.
 * When a conversion is inexact, the value returned is rounded according
 * to rounding control bits in MXCSR register.
 * Possible floating point exceptions: #I, #P
 */
void IA32_CPU::CVTSS2SI_GdWss(Ia32_Instruction_c *i)
{
   prepareSSE();

  Float32 op;

  if (i->modC0()) 
  {
    op = IA32_READ_XMM_REG_LO_DWORD(i->rm());
  }
  else 
  {
    read_virtual_dword(i->seg(), IA32_RMAddr(i), &op);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);

  Bit32u result = float32_to_int32(op, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_32BIT_REG(i->nnn(), result);

}

/* 
 * Opcode: 0F 5A
 * Convert two single precision FP numbers to two double precision FP numbers
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::CVTPS2PD_VpsWps(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: 66 0F 5A
 * Convert two double precision FP numbers to two single precision FP. 
 * When a conversion is inexact, the value returned is rounded according
 * to rounding control bits in MXCSR register.
 * Possible floating point exceptions: #I, #D, #O, #I, #P
 */
void IA32_CPU::CVTPD2PS_VpdWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 5A
 * Convert one double precision FP number to one single precision FP. 
 * When a conversion is inexact, the value returned is rounded according
 * to rounding control bits in MXCSR register.
 * Possible floating point exceptions: #I, #D, #O, #I, #P
 */
void IA32_CPU::CVTSD2SS_VsdWsd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F 5A
 * Convert one single precision FP number to one double precision FP. 
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::CVTSS2SD_VssWss(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: 0F 5B
 * Convert four signed integers to four single precision FP numbers.
 * When a conversion is inexact, the value returned is rounded according
 * to rounding control bits in MXCSR register.
 * Possible floating point exceptions: #P
 */
void IA32_CPU::CVTDQ2PS_VpsWdq(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: 66 0F 5B
 * Convert four single precision FP to four doubleword integers.
 * When a conversion is inexact, the value returned is rounded according
 * to rounding control bits in MXCSR register.
 * Possible floating point exceptions: #I, #P
 */
void IA32_CPU::CVTPS2DQ_VdqWps(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F 5B
 * Convert four single precision FP to four doubleword integers using 
 * truncation if the conversion is inexact.
 * Possible floating point exceptions: #I, #P
 */
void IA32_CPU::CVTTPS2DQ_VdqWps(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: 66 0F E6
 * Convert two double precision FP to two signed doubleword integers using 
 * truncation if the conversion is inexact.
 * Possible floating point exceptions: #I, #P
 */
void IA32_CPU::CVTTPD2DQ_VqWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F E6
 * Convert two double precision FP to two signed doubleword integers.
 * When a conversion is inexact, the value returned is rounded according
 * to rounding control bits in MXCSR register.
 * Possible floating point exceptions: #I, #P
 */
void IA32_CPU::CVTPD2DQ_VqWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F E6
 * Convert two 32bit signed integers from XMM/MEM to two double precision FP
 * Possible floating point exceptions: -
 */
void IA32_CPU::CVTDQ2PD_VpdWq(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: 0F 2E
 * Compare two single precision FP numbers and set EFLAGS accordintly.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::UCOMISS_VssWss(Ia32_Instruction_c *i)
{
   prepareSSE();

  Float32 op1 = IA32_READ_XMM_REG_LO_DWORD(i->nnn()), op2;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG_LO_DWORD(i->rm());
  }
  else 
  {
    read_virtual_dword(i->seg(), IA32_RMAddr(i), &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);

  if (MXCSR.get_DAZ()) 
  {
     op1 = handleDAZ(op1);
     op2 = handleDAZ(op2);
  }

  int rc = float32_compare_quiet(op1, op2, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
   write_eflags_fpu_compare(rc);

}

/* 
 * Opcode: 66 0F 2E
 * Compare two double precision FP numbers and set EFLAGS accordintly.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::UCOMISD_VsdWsd(Ia32_Instruction_c *i)            	
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: 0F 2F
 * Compare two single precision FP numbers and set EFLAGS accordintly.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::COMISS_VpsWps(Ia32_Instruction_c *i)
{
   prepareSSE();

  Float32 op1 = IA32_READ_XMM_REG_LO_DWORD(i->nnn()), op2;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG_LO_DWORD(i->rm());
  }
  else 
  {
    read_virtual_dword(i->seg(), IA32_RMAddr(i), &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);

  if (MXCSR.get_DAZ()) 
  {
     op1 = handleDAZ(op1);
     op2 = handleDAZ(op2);
  }

  int rc = float32_compare(op1, op2, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
   write_eflags_fpu_compare(rc);
}

/* 
 * Opcode: 66 0F 2F
 * Compare two double precision FP numbers and set EFLAGS accordintly.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::COMISD_VpdWpd(Ia32_Instruction_c *i)   
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: 0F 51
 * Square Root packed single precision.
 * Possible floating point exceptions: #I, #D, #P
 */
void IA32_CPU::SQRTPS_VpsWps(Ia32_Instruction_c *i)
{
   prepareSSE();

  Ia32PackedXmmRegister op, result;

  if (i->modC0()) 
  {
    op = IA32_READ_XMM_REG(i->rm());
  }
  else 
  {
    read_virtual_dqword_aligned(i->seg(), IA32_RMAddr(i), (Bit8u *) &op);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);

  if (MXCSR.get_DAZ()) 
  {
     op.xmm32u(0) = handleDAZ(op.xmm32u(0));
     op.xmm32u(1) = handleDAZ(op.xmm32u(1));
     op.xmm32u(2) = handleDAZ(op.xmm32u(2));
     op.xmm32u(3) = handleDAZ(op.xmm32u(3));
  }

  result.xmm32u(0) =  float32_sqrt(op.xmm32u(0), status_word);
  result.xmm32u(1) =  float32_sqrt(op.xmm32u(1), status_word);
  result.xmm32u(2) =  float32_sqrt(op.xmm32u(2), status_word);
  result.xmm32u(3) =  float32_sqrt(op.xmm32u(3), status_word);

   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG(i->nnn(), result);

}

/* 
 * Opcode: 66 0F 51
 * Square Root packed double precision.
 * Possible floating point exceptions: #I, #D, #P
 */
void IA32_CPU::SQRTPD_VpdWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 51
 * Square Root scalar double precision.
 * Possible floating point exceptions: #I, #D, #P
 */
void IA32_CPU::SQRTSD_VsdWsd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F 51
 * Square Root scalar single precision.
 * Possible floating point exceptions: #I, #D, #P
 */
void IA32_CPU::SQRTSS_VssWss(Ia32_Instruction_c *i)
{
   prepareSSE();

  Float32 op, result;

  if (i->modC0()) 
  {
    op = IA32_READ_XMM_REG_LO_DWORD(i->rm());
  }
  else 
  {
    read_virtual_dword(i->seg(), IA32_RMAddr(i), &op);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);
  if (MXCSR.get_DAZ()) op = handleDAZ(op);
  result = float32_sqrt(op, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG_LO_DWORD(i->nnn(), result);

}

/* 
 * Opcode: 0F 58
 * Add packed single precision FP numbers from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::ADDPS_VpsWps(Ia32_Instruction_c *i)
{
   prepareSSE();

  Ia32PackedXmmRegister op1 = IA32_READ_XMM_REG(i->nnn()), op2, result;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG(i->rm());
  }
  else 
  {
    read_virtual_dqword_aligned(i->seg(), IA32_RMAddr(i), (Bit8u *) &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);

  if (MXCSR.get_DAZ()) 
  {
	op1.xmm32u(0) = handleDAZ(op1.xmm32u(0));
	op1.xmm32u(1) = handleDAZ(op1.xmm32u(1));
	op1.xmm32u(2) = handleDAZ(op1.xmm32u(2));
	op1.xmm32u(3) = handleDAZ(op1.xmm32u(3));

	op2.xmm32u(0) = handleDAZ(op2.xmm32u(0));
	op2.xmm32u(1) = handleDAZ(op2.xmm32u(1));
	op2.xmm32u(2) = handleDAZ(op2.xmm32u(2));
	op2.xmm32u(3) = handleDAZ(op2.xmm32u(3));
  }

  result.xmm32u(0) = float32_add(op1.xmm32u(0), op2.xmm32u(0), status_word);
  result.xmm32u(1) = float32_add(op1.xmm32u(1), op2.xmm32u(1), status_word);
  result.xmm32u(2) = float32_add(op1.xmm32u(2), op2.xmm32u(2), status_word);
  result.xmm32u(3) = float32_add(op1.xmm32u(3), op2.xmm32u(3), status_word);

   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG(i->nnn(), result);

}

/* 
 * Opcode: 66 0F 58
 * Add packed double precision FP numbers from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::ADDPD_VpdWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 58
 * Add the lower double precision FP number from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::ADDSD_VsdWsd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F 58
 * Add the lower single precision FP number from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::ADDSS_VssWss(Ia32_Instruction_c *i)
{
   prepareSSE();

  Float32 op1 = IA32_READ_XMM_REG_LO_DWORD(i->nnn()), op2, result;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG_LO_DWORD(i->rm());
  }
  else 
  {
    read_virtual_dword(i->seg(), IA32_RMAddr(i), &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);

  if (MXCSR.get_DAZ()) 
  {
	op1 = handleDAZ(op1);
	op2 = handleDAZ(op2);
  }

  result = float32_add(op1, op2, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG_LO_DWORD(i->nnn(), result);

}

/* 
 * Opcode: 0F 59
 * Multiply packed single precision FP numbers from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::MULPS_VpsWps(Ia32_Instruction_c *i)
{
   prepareSSE();
  Ia32PackedXmmRegister op1 = IA32_READ_XMM_REG(i->nnn()), op2, result;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG(i->rm());
  }
  else 
  {
    read_virtual_dqword_aligned(i->seg(), IA32_RMAddr(i), (Bit8u *) &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);
  if (MXCSR.get_DAZ()) 
  {
	op1.xmm32u(0) = handleDAZ(op1.xmm32u(0));
	op1.xmm32u(1) = handleDAZ(op1.xmm32u(1));
	op1.xmm32u(2) = handleDAZ(op1.xmm32u(2));
	op1.xmm32u(3) = handleDAZ(op1.xmm32u(3));

	op2.xmm32u(0) = handleDAZ(op2.xmm32u(0));
	op2.xmm32u(1) = handleDAZ(op2.xmm32u(1));
	op2.xmm32u(2) = handleDAZ(op2.xmm32u(2));
	op2.xmm32u(3) = handleDAZ(op2.xmm32u(3));
  }

  result.xmm32u(0) = float32_mul(op1.xmm32u(0), op2.xmm32u(0), status_word);
  result.xmm32u(1) = float32_mul(op1.xmm32u(1), op2.xmm32u(1), status_word);
  result.xmm32u(2) = float32_mul(op1.xmm32u(2), op2.xmm32u(2), status_word);
  result.xmm32u(3) = float32_mul(op1.xmm32u(3), op2.xmm32u(3), status_word);

   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG(i->nnn(), result);

}

/* 
 * Opcode: 66 0F 59
 * Multiply packed double precision FP numbers from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::MULPD_VpdWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 59
 * Multiply the lower double precision FP number from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::MULSD_VsdWsd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F 59
 * Multiply the lower single precision FP number from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::MULSS_VssWss(Ia32_Instruction_c *i)
{
   prepareSSE();

  Float32 op1 = IA32_READ_XMM_REG_LO_DWORD(i->nnn()), op2, result;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG_LO_DWORD(i->rm());
  }
  else 
  {
    read_virtual_dword(i->seg(), IA32_RMAddr(i), &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);

  if (MXCSR.get_DAZ()) 
  {
	op1 = handleDAZ(op1);
	op2 = handleDAZ(op2);
  }

  result = float32_mul(op1, op2, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG_LO_DWORD(i->nnn(), result);

}

/* 
 * Opcode: 0F 5C
 * Subtract packed single precision FP numbers from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::SUBPS_VpsWps(Ia32_Instruction_c *i)
{
   prepareSSE();

  Ia32PackedXmmRegister op1 = IA32_READ_XMM_REG(i->nnn()), op2, result;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG(i->rm());
  }
  else 
  {
    read_virtual_dqword_aligned(i->seg(), IA32_RMAddr(i), (Bit8u *) &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);

  if (MXCSR.get_DAZ()) 
  {
	op1.xmm32u(0) = handleDAZ(op1.xmm32u(0));
	op1.xmm32u(1) = handleDAZ(op1.xmm32u(1));
	op1.xmm32u(2) = handleDAZ(op1.xmm32u(2));
	op1.xmm32u(3) = handleDAZ(op1.xmm32u(3));

	op2.xmm32u(0) = handleDAZ(op2.xmm32u(0));
	op2.xmm32u(1) = handleDAZ(op2.xmm32u(1));
	op2.xmm32u(2) = handleDAZ(op2.xmm32u(2));
	op2.xmm32u(3) = handleDAZ(op2.xmm32u(3));
  }

  result.xmm32u(0) = float32_sub(op1.xmm32u(0), op2.xmm32u(0), status_word);
  result.xmm32u(1) = float32_sub(op1.xmm32u(1), op2.xmm32u(1), status_word);
  result.xmm32u(2) = float32_sub(op1.xmm32u(2), op2.xmm32u(2), status_word);
  result.xmm32u(3) = float32_sub(op1.xmm32u(3), op2.xmm32u(3), status_word);

   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG(i->nnn(), result);

}

/* 
 * Opcode: 66 0F 5C
 * Subtract packed double precision FP numbers from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::SUBPD_VpdWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 5C
 * Subtract the lower double precision FP number from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::SUBSD_VsdWsd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F 5C
 * Subtract the lower single precision FP number from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::SUBSS_VssWss(Ia32_Instruction_c *i)
{
   prepareSSE();

  Float32 op1 = IA32_READ_XMM_REG_LO_DWORD(i->nnn()), op2, result;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG_LO_DWORD(i->rm());
  }
  else 
  {
    read_virtual_dword(i->seg(), IA32_RMAddr(i), &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);

  if (MXCSR.get_DAZ()) 
  {
	op1 = handleDAZ(op1);
	op2 = handleDAZ(op2);
  }

  result = float32_sub(op1, op2, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG_LO_DWORD(i->nnn(), result);
}

/* 
 * Opcode: 0F 5D
 * Calculate the minimum single precision FP between XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::MINPS_VpsWps(Ia32_Instruction_c *i)
{
   prepareSSE();
  Ia32PackedXmmRegister op1 = IA32_READ_XMM_REG(i->nnn()), op2, result;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG(i->rm());
  }
  else 
  {
    read_virtual_dqword_aligned(i->seg(), IA32_RMAddr(i), (Bit8u *) &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);
  int rc;

  if (MXCSR.get_DAZ()) 
  {
	op1.xmm32u(0) = handleDAZ(op1.xmm32u(0));
	op1.xmm32u(1) = handleDAZ(op1.xmm32u(1));
	op1.xmm32u(2) = handleDAZ(op1.xmm32u(2));
	op1.xmm32u(3) = handleDAZ(op1.xmm32u(3));

	op2.xmm32u(0) = handleDAZ(op2.xmm32u(0));
	op2.xmm32u(1) = handleDAZ(op2.xmm32u(1));
	op2.xmm32u(2) = handleDAZ(op2.xmm32u(2));
	op2.xmm32u(3) = handleDAZ(op2.xmm32u(3));
  }

  rc = float32_compare(op1.xmm32u(0), op2.xmm32u(0), status_word);
  result.xmm32u(0) =  (rc == float_relation_less) ? op1.xmm32u(0) : op2.xmm32u(0);
  rc = float32_compare(op1.xmm32u(1), op2.xmm32u(1), status_word);
  result.xmm32u(1) =  (rc == float_relation_less) ? op1.xmm32u(1) : op2.xmm32u(1);
  rc = float32_compare(op1.xmm32u(2), op2.xmm32u(2), status_word);
  result.xmm32u(2) =  (rc == float_relation_less) ? op1.xmm32u(2) : op2.xmm32u(2);
  rc = float32_compare(op1.xmm32u(3), op2.xmm32u(3), status_word);
  result.xmm32u(3) =  (rc == float_relation_less) ? op1.xmm32u(3) : op2.xmm32u(3);

   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG(i->nnn(), result);

}

/* 
 * Opcode: 66 0F 5D
 * Calculate the minimum double precision FP between XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::MINPD_VpdWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 5D
 * Calculate the minimum scalar double precision FP between XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::MINSD_VsdWsd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F 5D
 * Calculate the minimum scalar single precision FP between XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::MINSS_VssWss(Ia32_Instruction_c *i)
{
   prepareSSE();
  Float32 op1 = IA32_READ_XMM_REG_LO_DWORD(i->nnn()), op2;
  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG_LO_DWORD(i->rm());
  }
  else 
  {
    read_virtual_dword(i->seg(), IA32_RMAddr(i), &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);
  if (MXCSR.get_DAZ()) 
  {
	op1 = handleDAZ(op1);
	op2 = handleDAZ(op2);
  }

  int rc = float32_compare(op1, op2, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG_LO_DWORD(i->nnn(), (rc == float_relation_less) ? op1 : op2);

}

/* 
 * Opcode: 0F 5E
 * Divide packed single precision FP numbers from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #Z, #O, #U, #P
 */
void IA32_CPU::DIVPS_VpsWps(Ia32_Instruction_c *i)
{
   prepareSSE();
  Ia32PackedXmmRegister op1 = IA32_READ_XMM_REG(i->nnn()), op2, result;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG(i->rm());
  }
  else 
  {
    read_virtual_dqword_aligned(i->seg(), IA32_RMAddr(i), (Bit8u *) &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);

  if (MXCSR.get_DAZ()) 
  {
	op1.xmm32u(0) = handleDAZ(op1.xmm32u(0));
	op1.xmm32u(1) = handleDAZ(op1.xmm32u(1));
	op1.xmm32u(2) = handleDAZ(op1.xmm32u(2));
	op1.xmm32u(3) = handleDAZ(op1.xmm32u(3));

	op2.xmm32u(0) = handleDAZ(op2.xmm32u(0));
	op2.xmm32u(1) = handleDAZ(op2.xmm32u(1));
	op2.xmm32u(2) = handleDAZ(op2.xmm32u(2));
	op2.xmm32u(3) = handleDAZ(op2.xmm32u(3));
  }

  result.xmm32u(0) = float32_div(op1.xmm32u(0), op2.xmm32u(0), status_word);
  result.xmm32u(1) = float32_div(op1.xmm32u(1), op2.xmm32u(1), status_word);
  result.xmm32u(2) = float32_div(op1.xmm32u(2), op2.xmm32u(2), status_word);
  result.xmm32u(3) = float32_div(op1.xmm32u(3), op2.xmm32u(3), status_word);

   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG(i->nnn(), result);

}

/* 
 * Opcode: 66 0F 5E
 * Divide packed double precision FP numbers from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #Z, #O, #U, #P
 */
void IA32_CPU::DIVPD_VpdWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 5E
 * Divide the lower double precision FP number from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #Z, #O, #U, #P
 */
void IA32_CPU::DIVSD_VsdWsd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F 5E
 * Divide the lower single precision FP number from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #Z, #O, #U, #P
 */
void IA32_CPU::DIVSS_VssWss(Ia32_Instruction_c *i)
{
   prepareSSE();

  Float32 op1 = IA32_READ_XMM_REG_LO_DWORD(i->nnn()), op2, result;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG_LO_DWORD(i->rm());
  }
  else 
  {
    read_virtual_dword(i->seg(), IA32_RMAddr(i), &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);
  if (MXCSR.get_DAZ()) 
  {
	op1 = handleDAZ(op1);
	op2 = handleDAZ(op2);
  }

  result = float32_div(op1, op2, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG_LO_DWORD(i->nnn(), result);

}

/* 
 * Opcode: 0F 5F
 * Calculate the maximum single precision FP between XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::MAXPS_VpsWps(Ia32_Instruction_c *i)
{
   prepareSSE();
  Ia32PackedXmmRegister op1 = IA32_READ_XMM_REG(i->nnn()), op2, result;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG(i->rm());
  }
  else 
  {
    read_virtual_dqword_aligned(i->seg(), IA32_RMAddr(i), (Bit8u *) &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);
  int rc;

  if (MXCSR.get_DAZ()) 
  {
	op1.xmm32u(0) = handleDAZ(op1.xmm32u(0));
	op1.xmm32u(1) = handleDAZ(op1.xmm32u(1));
	op1.xmm32u(2) = handleDAZ(op1.xmm32u(2));
	op1.xmm32u(3) = handleDAZ(op1.xmm32u(3));

	op2.xmm32u(0) = handleDAZ(op2.xmm32u(0));
	op2.xmm32u(1) = handleDAZ(op2.xmm32u(1));
	op2.xmm32u(2) = handleDAZ(op2.xmm32u(2));
	op2.xmm32u(3) = handleDAZ(op2.xmm32u(3));
  }

  rc = float32_compare(op1.xmm32u(0), op2.xmm32u(0), status_word);
  result.xmm32u(0) =  (rc == float_relation_greater) ? op1.xmm32u(0) : op2.xmm32u(0);
  rc = float32_compare(op1.xmm32u(1), op2.xmm32u(1), status_word);
  result.xmm32u(1) =  (rc == float_relation_greater) ? op1.xmm32u(1) : op2.xmm32u(1);
  rc = float32_compare(op1.xmm32u(2), op2.xmm32u(2), status_word);
  result.xmm32u(2) =  (rc == float_relation_greater) ? op1.xmm32u(2) : op2.xmm32u(2);
  rc = float32_compare(op1.xmm32u(3), op2.xmm32u(3), status_word);
  result.xmm32u(3) =  (rc == float_relation_greater) ? op1.xmm32u(3) : op2.xmm32u(3);

   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG(i->nnn(), result);

}

/* 
 * Opcode: 66 0F 5F
 * Calculate the maximum double precision FP between XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::MAXPD_VpdWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 5F
 * Calculate the maximum scalar double precision FP between XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::MAXSD_VsdWsd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F 5F
 * Calculate the maxumim scalar single precision FP between XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::MAXSS_VssWss(Ia32_Instruction_c *i)
{
   prepareSSE();
  Float32 op1 = IA32_READ_XMM_REG_LO_DWORD(i->nnn()), op2;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG_LO_DWORD(i->rm());
  }
  else 
  {
    read_virtual_dword(i->seg(), IA32_RMAddr(i), &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);
  if (MXCSR.get_DAZ()) 
  {
	op1 = handleDAZ(op1);
	op2 = handleDAZ(op2);
  }

  int rc = float32_compare(op1, op2, status_word);
   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG_LO_DWORD(i->nnn(), (rc == float_relation_greater) ? op1 : op2);

}

/* 
 * Opcode: 66 0F 7C
 * Add horizontally packed double precision FP in XMM2/MEM from XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::HADDPD_VpdWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 7C
 * Add horizontally packed single precision FP in XMM2/MEM from XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::HADDPS_VpsWps(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: 66 0F 7D
 * Subtract horizontally packed double precision FP in XMM2/MEM from XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::HSUBPD_VpdWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F 7D
 * Subtract horizontally packed single precision FP in XMM2/MEM from XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::HSUBPS_VpsWps(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: 0F C2
 * Compare packed single precision FP values using Ib as comparison predicate.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::CMPPS_VpsWpsIb(Ia32_Instruction_c *i)
{
   prepareSSE();

  Ia32PackedXmmRegister op1 = IA32_READ_XMM_REG(i->nnn()), op2, result;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG(i->rm());
  }
  else 
  {
    read_virtual_dqword_aligned(i->seg(), IA32_RMAddr(i), (Bit8u *) &op2);
  }

  float_status_t status;
  mxcsr_to_softfloat_status_word(status, MXCSR);
  int ib = i->Ib();

  if (MXCSR.get_DAZ()) 
  {
	op1.xmm32u(0) = handleDAZ(op1.xmm32u(0));
	op1.xmm32u(1) = handleDAZ(op1.xmm32u(1));
	op1.xmm32u(2) = handleDAZ(op1.xmm32u(2));
	op1.xmm32u(3) = handleDAZ(op1.xmm32u(3));

	op2.xmm32u(0) = handleDAZ(op2.xmm32u(0));
	op2.xmm32u(1) = handleDAZ(op2.xmm32u(1));
	op2.xmm32u(2) = handleDAZ(op2.xmm32u(2));
	op2.xmm32u(3) = handleDAZ(op2.xmm32u(3));
  }

  if(ib < 4) 
  {
    result.xmm32u(0) = compare32[ib](op1.xmm32u(0), op2.xmm32u(0), status) ? 0xFFFFFFFF : 0;
    result.xmm32u(1) = compare32[ib](op1.xmm32u(1), op2.xmm32u(1), status) ? 0xFFFFFFFF : 0;
    result.xmm32u(2) = compare32[ib](op1.xmm32u(2), op2.xmm32u(2), status) ? 0xFFFFFFFF : 0;
    result.xmm32u(3) = compare32[ib](op1.xmm32u(3), op2.xmm32u(3), status) ? 0xFFFFFFFF : 0;
  }
  else 
	if(ib < 8)
	{
		ib -= 4;

		result.xmm32u(0) = compare32[ib](op1.xmm32u(0), op2.xmm32u(0), status) ? 0 : 0xFFFFFFFF;
		result.xmm32u(1) = compare32[ib](op1.xmm32u(1), op2.xmm32u(1), status) ? 0 : 0xFFFFFFFF;
		result.xmm32u(2) = compare32[ib](op1.xmm32u(2), op2.xmm32u(2), status) ? 0 : 0xFFFFFFFF;
		result.xmm32u(3) = compare32[ib](op1.xmm32u(3), op2.xmm32u(3), status) ? 0 : 0xFFFFFFFF;
	}
    else 
    {
    //BX_PANIC(("CMPPS_VpsWpsIb: unrecognized predicate %u", ib));
    }

   check_exceptionsSSE(status.float_exception_flags);
  IA32_WRITE_XMM_REG(i->nnn(), result);

}

/* 
 * Opcode: 66 0F C2
 * Compare packed double precision FP values using Ib as comparison predicate.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::CMPPD_VpdWpdIb(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F C2
 * Compare double precision FP values using Ib as comparison predicate.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::CMPSD_VsdWsdIb(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F3 0F C2
 * Compare single precision FP values using Ib as comparison predicate.
 * Possible floating point exceptions: #I, #D
 */
void IA32_CPU::CMPSS_VssWssIb(Ia32_Instruction_c *i)
{
   prepareSSE();

  Float32 op1 = IA32_READ_XMM_REG_LO_DWORD(i->nnn()), op2, result = 0;

  if (i->modC0()) 
  {
    op2 = IA32_READ_XMM_REG_LO_DWORD(i->rm());
  }
  else 
  {
    read_virtual_dword(i->seg(), IA32_RMAddr(i), (Bit32u *) &op2);
  }

  float_status_t status_word;
  mxcsr_to_softfloat_status_word(status_word, MXCSR);
  int ib = i->Ib();
  if (MXCSR.get_DAZ()) 
  {
	op1 = handleDAZ(op1);
	op2 = handleDAZ(op2);
  }

  if(ib < 4) 
  {
     if(compare32[ib](op1, op2, status_word)) 
	 {
        result = 0xFFFFFFFF;
     } 
	 else 
	 {
        result = 0;
     }
  } else 
	  if(ib < 8) 
	  {
		if(compare32[ib-4](op1, op2, status_word)) 
		{
			result = 0;
		} 
		else 
		{
			result = 0xFFFFFFFF;
		}
	 } 
	 else 
	 {
		//BX_PANIC(("CMPPS_VssWssIb: unrecognized predicate %u", ib));
	 }

   check_exceptionsSSE(status_word.float_exception_flags);
  IA32_WRITE_XMM_REG_LO_DWORD(i->nnn(), result);

}

/* 
 * Opcode: 66 0F D0
 * Add/Subtract packed double precision FP numbers from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::ADDSUBPD_VpdWpd(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}

/* 
 * Opcode: F2 0F D0
 * Add/Substract packed single precision FP numbers from XMM2/MEM to XMM1.
 * Possible floating point exceptions: #I, #D, #O, #U, #P
 */
void IA32_CPU::ADDSUBPS_VpsWps(Ia32_Instruction_c *i)
{
  UndefinedOpcode(i);
}
